package com.sinodata.bsm.center.web.action.resource.tree;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.log4j.Logger;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.springframework.beans.factory.annotation.Autowired;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.Preparable;
import com.sinodata.bsm.center.cache.MotiResRelCache;
import com.sinodata.bsm.center.cache.ResCache;
import com.sinodata.bsm.center.cache.ResGroupCache;
import com.sinodata.bsm.center.cache.ResRelationCache;
import com.sinodata.bsm.center.cache.ResTypeCache;
import com.sinodata.bsm.center.cache.ResTypeDispConfCache;
import com.sinodata.bsm.center.cache.TreeNodeSequenceCache;
import com.sinodata.bsm.center.service.relation.ResRelationService;
import com.sinodata.bsm.center.service.resource.ResService;
import com.sinodata.bsm.center.service.resource.ResViewService;
import com.sinodata.bsm.common.vo.MotiResRel;
import com.sinodata.bsm.common.vo.Res;
import com.sinodata.bsm.common.vo.ResGroup;
import com.sinodata.bsm.common.vo.ResRelation;
import com.sinodata.bsm.common.vo.ResType;
import com.sinodata.bsm.common.vo.ResTypeDispConf;
import com.sinodata.bsm.common.vo.ResView;

public abstract class AbstractTreeAction extends ActionSupport implements Preparable, ServletRequestAware, ServletResponseAware {

    private static final long serialVersionUID = -1653204626115064950L;

    protected static final Logger logger = Logger.getLogger(AbstractTreeAction.class);
    @Autowired
    protected ResViewService resViewService;
    @Autowired
    protected ResService resService;
    @Autowired
    protected ResRelationService resRelationService;
    @Autowired
    protected ResRelationCache resRelationCache;
    @Autowired
    protected ResTypeDispConfCache resTypeDispConfCache;
    @Autowired
    protected TreeNodeSequenceCache treeNodeSequenceCache;
    @Autowired
    protected MotiResRelCache motiResRelCache;
    @Autowired
    protected ResGroupCache resGroupCache;
    @Autowired
    protected ResTypeCache resTypeCache;
    @Autowired
    protected ResCache resCache;

    /**
     * HttpServletRequest对象
     */
    protected HttpServletRequest request;

    /**
     * HttpServletResponse对象
     */
    protected HttpServletResponse response;

    /**
     * 设置HttpServletRequest
     */
    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;

    }

    /**
     * 设置HttpServletResponse
     */
    @Override
    public void setServletResponse(HttpServletResponse arg0) {
        response = arg0;
    }

    public AbstractTreeAction() {
        super();
    }

    /**
     * 加载一个父资源下的子资源和子资源组
     * @param parentResId
     * @param relationTypesIds
     * @return
     */
    protected JSONArray loadChildNode(Long parentResId, Set<Long> relationTypesIds) {
        JSONArray jsonArray = new JSONArray();
        List<ResGroup> groups = resGroupCache.findByResId(parentResId.longValue());
        Map<Long, List<ResGroup>> tmpMap = new LinkedHashMap<Long, List<ResGroup>>();
        List<ResGroup> rootResGroup = new ArrayList<ResGroup>();
        if (groups == null) {
            groups = new ArrayList<ResGroup>(0);
        }
        Set<Long> excludeSet = new HashSet<Long>();
        for (ResGroup g : groups) {
            if (g.getParentId() != null) {
                List<ResGroup> arr = tmpMap.get(g.getParentId().longValue());
                if (arr == null) {
                    arr = new ArrayList<ResGroup>();
                    tmpMap.put(g.getParentId().longValue(), arr);
                }
                arr.add(g);
            } else {
                rootResGroup.add(g);
            }
            List<MotiResRel> relList = motiResRelCache.findByResGroupId(g.getId());
            if (relList != null) {
                for (MotiResRel rel : relList) {
                    excludeSet.add(rel.getResId());
                }
            }
        }
        for (ResGroup g : rootResGroup) {
            JSONObject gjson = genResGroupNode2(g, tmpMap, relationTypesIds, new ArrayList(0));
            jsonArray.add(gjson);
        }
        //////////////////////////////////////////////////////
        List<ResRelation> relations = resRelationCache.getResRelationsOfRes(parentResId);
        List<Res> children = new ArrayList<Res>();
        if (relations != null) {
            Res child = null;
            for (ResRelation resRelation : relations) {
                if (!excludeSet.contains(resRelation.getEndId().longValue()) && resRelation.getStartId().longValue() == parentResId.longValue() && relationTypesIds.contains(resRelation.getRelationTypeId().longValue())) {
                    if ((child = resService.get(resRelation.getEndId())) != null) {
                        children.add(child);
                    }

                }
            }
        }
        //将同一资源类型的资源 放一个List集合中
        List<List<Res>> types = new ArrayList<List<Res>>();
        for (Res child : children) {
            List<Res> type = null;
            for (int j = 0; j < types.size(); j++) {
                if (types.get(j).get(0).getResTypeId().longValue() == child.getResTypeId().longValue()) {
                    type = types.get(j);
                    break;
                }
            }
            if (type == null) {
                type = new ArrayList<Res>();
                types.add(type);
            }
            type.add(child);
        }
        for (List<Res> type : types) {
            if (type.size() == 1) {
                JSONObject childRes = genResNode(type.get(0), parentResId, relationTypesIds);
                jsonArray.add(childRes);
            } else {
                JSONArray childArray = new JSONArray();
                int maxStatus = 0;
                int pausedSize = 0;
                for (int j = 0; j < type.size(); j++) {
                    Res cRes = type.get(j);
                    if (cRes.getHealthStatus() > maxStatus) {
                        maxStatus = cRes.getHealthStatus();
                    }
                    if (cRes.getPaused() == 1) {
                        pausedSize++;
                    }
                    JSONObject childRes = genResNode(cRes, parentResId, relationTypesIds);
                    childArray.add(childRes);
                }
                ResTypeDispConf conf = resTypeDispConfCache.find(parentResId, type.get(0).getResTypeId());
                boolean showTypeNode = true;
                String typename = null;
                if (conf != null) {
                    showTypeNode = conf.getIsDisp() == 1 ? true : false;
                    typename = conf.getDispName() == null ? null : conf.getDispName();
                }
                if (showTypeNode) {
                    ResType resType = resTypeCache.get(type.get(0).getResTypeId());
                    JSONObject typeNode = genResTypeNode(resType, parentResId);
                    if (typename != null) {
                        typeNode.element("name", typename);
                    }
                    int status = type.size() == pausedSize ? 0 : maxStatus;
                    typeNode.element("iconSkin", "type" + status);
                    NodePrivilegeUtil.getStatusCache(request, this.viewId).put("3|" + resType.getId() + "|" + parentResId, new Integer[] { status, 1 });
                    typeNode.element("children", childArray);
                    jsonArray.add(typeNode);
                } else {
                    jsonArray.addAll(childArray);
                }
            }
        }

        return jsonArray;
    }

    /**
     * 加载最后一次的树节点
     * @param resjson
     * @param nodeTrace
     * @param relationTypesIds
     */
    protected void loadResNodeTrace(JSONObject resjson, List<String> nodeTrace, Set<Long> relationTypesIds) {
        if (nodeTrace.contains(resjson.getString("id"))) {
            if (nodeTrace.get(nodeTrace.size() - 1).equals(resjson.getString("id"))) {
                return;
            }
            resjson.element("open", true);
        }
        String[] idArr = resjson.getString("id").split("[|]");
        JSONArray children = null;
        if (idArr[0].equals("5") || idArr[0].equals("3")) {
            children = resjson.getJSONArray("children");
        } else {
            children = loadChildNode(Long.parseLong(idArr[1]), relationTypesIds);
        }
        NodeCompare.sortChildNodeSequence(resjson.getString("id"), children);
        resjson.element("children", children);
        for (int i = 0; i < children.size(); i++) {
            JSONObject obj = children.getJSONObject(i);
            idArr = obj.getString("id").split("[|]");
            if (nodeTrace.contains(obj.getString("id"))) {
                loadResNodeTrace(obj, nodeTrace, relationTypesIds);
            }
        }
    }

    /**
     * 一个资源下的构建的资源组节点
     * @param g
     * @param childMap
     * @param relationTypesIds
     * @return
     */
    protected JSONObject genResGroupNode2(ResGroup g, Map<Long, List<ResGroup>> childMap, Set<Long> relationTypesIds, List<String> traceList) {
        JSONObject json = new JSONObject();
        long pid = g.getParentId() == null ? 0 : g.getParentId();
        String nodeId = TreeConstants.NODE_TYPE_RESGROUP + "|" + g.getId() + "|" + pid;
        json.element("id", nodeId);
        if (traceList.contains(nodeId)) {
            json.element("open", true);
        }
        List<MotiResRel> relList = motiResRelCache.findByResGroupId(g.getId());
        JSONArray arr = new JSONArray();

        int maxStatus = 1;
        if (childMap.containsKey(g.getId().longValue())) {
            List<ResGroup> children = childMap.get(g.getId().longValue());
            for (ResGroup child : children) {
                JSONObject childJson = genResGroupNode2(child, childMap, relationTypesIds, traceList);

                if (maxStatus < childJson.getInt("maxStatus")) {
                    maxStatus = childJson.getInt("maxStatus");
                }
                arr.add(childJson);
            }
        }
        if (relList != null) {
            for (MotiResRel rel : relList) {
                Res res = null;
                if ((res = resService.get(rel.getResId())) != null && NodePrivilegeUtil.hasResViewPrivilege(res.getId(), relationTypesIds, request)) {
                    JSONObject resjson = genResNode(res, 0L, relationTypesIds);
                    if (traceList.contains("2|" + res.getId() + "|0")) {
                        loadResNodeTrace(resjson, traceList, relationTypesIds);
                    }
                    arr.add(resjson);
                    if (maxStatus < res.getHealthStatus()) {
                        maxStatus = res.getHealthStatus();
                    }

                }
            }
        }

        json.element("maxStatus", maxStatus);
        json.element("iconSkin", "type" + maxStatus);

        json.element("name", g.getName());
        NodePrivilegeUtil.getStatusCache(request, this.viewId).put(nodeId, new Integer[] { maxStatus, 0 });
        json.element("isParent", arr.size() > 0);

        json.element("children", arr);
        return json;
    }

    @Override
    public String execute() throws Exception {
        try {
            if (this.id != null) {
                renderText(children().toString());

            } else {
                renderText(root().toString());
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    protected abstract JSONArray children() throws Exception;

    protected abstract JSONArray root() throws Exception;

    @Override
    public void prepare() throws Exception {
        // TODO Auto-generated method stub

    }

    protected String id;
    protected Long viewId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Long getViewId() {
        return viewId;
    }

    public void setViewId(Long viewId) {
        this.viewId = viewId;
    }

    /**
     * 生成资源节点
     * @param res
     * @param parentResId
     * @param relationTypesIds
     * @return
     */
    protected JSONObject genResNode(Res res, Long parentResId, Set<Long> relationTypesIds) {
        JSONObject json = new JSONObject();
        String nodeId = "2|" + res.getId() + "|" + parentResId;
        json.element("id", nodeId);
        json.element("name", res.getName());
        int status = res.getPaused() == 1 ? 0 : res.getHealthStatus();
        json.element("iconSkin", "res" + status);
        NodePrivilegeUtil.getStatusCache(request, this.viewId).put(nodeId, new Integer[] { res.getHealthStatus(), 1 });
        List groups = resGroupCache.findByResId(res.getId().longValue());
        boolean isParent = resRelationService.hasChild(res.getId(), relationTypesIds) || (groups != null && groups.size() > 0);
        json.element("isParent", isParent);
        return json;
    }

    /**
     * 资源类别节点
     * @param resType
     * @param resId
     * @return
     */
    protected JSONObject genResTypeNode(ResType resType, Long resId) {
        JSONObject json = new JSONObject();
        json.element("id", "3|" + resType.getId() + "|" + resId);
        json.element("name", resType.getName());
        json.element("isParent", true);
        return json;
    }

    /**
     * 资源视图节点
     * @param view
     * @return
     */
    protected JSONObject genResViewNode(ResView view) {
        JSONObject json = new JSONObject();
        json.element("id", "1|" + view.getId() + "|0");
        json.element("name", view.getName());
        json.element("open", true);
        json.element("nocheck", true);
        json.element("isParent", true);
        return json;
    }

    /**
     * 向前台写数据
     * 
     * @param text
     */
    protected void renderText(final String text) {
        render(text, "UTF-8");
    }

    private void render(final String text, final String contentType) {
        response.setCharacterEncoding(contentType);// 设置字符集编码
        response.setContentType("text/html;charset=" + contentType);// 页面先设置了编码集,用上方法设置response编码集
        try {
            response.getWriter().write(text);
            response.getWriter().flush();
        } catch (IOException e) {
            logger.error(e.getMessage(), e);
        }
    }

}
